package org.fast.easy.auth.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthUser;
import org.fast.easy.auth.properties.CaptchaProperties;
import org.fast.easy.auth.properties.UserPasswordProperties;
import org.fast.easy.common.i18n.util.MessageUtils;
import org.fast.easy.core.constant.Constants;
import org.fast.easy.core.constant.TenantConstants;
import org.fast.easy.core.domain.auth.dto.RoleDTO;
import org.fast.easy.core.domain.auth.form.RegisterBody;
import org.fast.easy.core.domain.auth.model.LoginUser;
import org.fast.easy.core.domain.auth.model.XcxLoginUser;
import org.fast.easy.core.enums.UserStatus;
import org.fast.easy.core.exception.ServiceException;
import org.fast.easy.core.util.DateUtils;
import org.fast.easy.core.util.StringUtils;
import org.fast.easy.framework.exception.user.UserException;
import org.fast.easy.framework.mybatis.helper.DataPermissionHelper;
import org.fast.easy.framework.tenant.exception.TenantException;
import org.fast.easy.framework.tenant.helper.TenantHelper;
import org.fast.easy.system.core.service.ISysConfigService;
import org.fast.easy.system.upms.domain.bo.SysSocialBo;
import org.fast.easy.system.upms.domain.bo.SysUserBo;
import org.fast.easy.system.upms.domain.entity.SysUser;
import org.fast.easy.system.upms.domain.vo.SysSocialVo;
import org.fast.easy.system.upms.domain.vo.SysTenantVo;
import org.fast.easy.system.upms.domain.vo.SysUserVo;
import org.fast.easy.system.upms.mapper.SysUserMapper;
import org.fast.easy.system.upms.service.ISysPermissionService;
import org.fast.easy.system.upms.service.ISysSocialService;
import org.fast.easy.system.upms.service.ISysTenantService;
import org.fast.easy.system.upms.service.ISysUserService;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;

/**
 * 登录校验方法
 *
 * @author ruoyi
 */
@Service
@Slf4j
public class SysLoginService extends AbstractSysLoginService implements ISysLoginService {
    @Resource
    private ISysTenantService tenantService;
    @Resource
    private ISysPermissionService permissionService;
    @Resource
    private ISysSocialService sysSocialService;
    @Resource
    private ISysUserService userService;
    @Resource
    private SysUserMapper userMapper;
    @Resource
    private ISysConfigService configService;

    @Resource
    private UserPasswordProperties userPasswordProperties;
    @Resource
    private CaptchaProperties captchaProperties;

    public SysLoginService(UserPasswordProperties userPasswordProperties, CaptchaProperties captchaProperties) {
        super(userPasswordProperties, captchaProperties);
    }



    /**
     * 绑定第三方用户
     *
     * @param authUserData 授权响应实体
     */
    @Override
    public void socialRegister(AuthUser authUserData) {
        SysSocialBo bo = getSysSocialBo(authUserData);
        String authId = bo.getAuthId();
        // 查询是否已经绑定用户
        List<SysSocialVo> list = sysSocialService.selectByAuthId(authId);
        if (CollUtil.isEmpty(list)) {
            // 没有绑定用户, 新增用户信息
            sysSocialService.insertByBo(bo);
        } else {
            // 更新用户信息
            bo.setId(list.get(0).getId());
            sysSocialService.updateByBo(bo);
        }
    }


    /**
     * 注册
     */
    @Override
    public void register(RegisterBody registerBody) {
        String tenantId = registerBody.getTenantId();
        SysUserBo sysUserBo = getSysUserBo(registerBody);

        String username = sysUserBo.getUserName();
        boolean exist = TenantHelper.dynamic(tenantId, () -> {
            if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) {
                throw new ServiceException("当前系统没有开启注册功能");
            }
            return userService.exists(sysUserBo);
        });
        if (exist) {
            throw new UserException("user.register.save.error", username);
        }

        boolean regFlag =  userService.registerUser(sysUserBo, tenantId);
        if (!regFlag) {
            throw new UserException("user.register.error");
        }
        recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.register.success"));
    }

    @Override
    public LoginUser getLoginUserInfoByUsername(String username, String tenantId) {
        return TenantHelper.dynamic(tenantId, () -> {
            SysUser sysUser = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
                    .select(SysUser::getUserName, SysUser::getStatus)
                    .eq(SysUser::getUserName, username));
            if (ObjectUtil.isNull(sysUser)) {
                throw new UserException("user.not.exists", username);
            }
            if (UserStatus.DISABLE.getCode().equals(sysUser.getStatus())) {
                throw new UserException("user.blocked", username);
            }
            // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
            // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
            return buildLoginUser(userMapper.selectUserByUserName(username));
        });
    }

    @Override
    public LoginUser getLoginUserInfoByUserId(Long userId, String tenantId) {
        return TenantHelper.dynamic(tenantId, () -> {
            SysUser sysUser = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
                    .select(SysUser::getUserName, SysUser::getStatus)
                    .eq(SysUser::getUserId, userId));
            if (ObjectUtil.isNull(sysUser)) {
                throw new UserException("user.not.exists", "");
            }
            if (UserStatus.DISABLE.getCode().equals(sysUser.getStatus())) {
                throw new UserException("user.blocked", sysUser.getUserName());
            }
            // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
            // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
            return buildLoginUser(userMapper.selectUserByUserName(sysUser.getUserName()));
        });
    }

    @Override
    public LoginUser getLoginUserInfoByPhonenumber(String phonenumber, String tenantId) {
        return TenantHelper.dynamic(tenantId, () -> {
            SysUser sysUser = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
                    .select(SysUser::getPhonenumber, SysUser::getStatus)
                    .eq(SysUser::getPhonenumber, phonenumber));
            if (ObjectUtil.isNull(sysUser)) {
                throw new UserException("user.not.exists", phonenumber);
            }
            if (UserStatus.DISABLE.getCode().equals(sysUser.getStatus())) {
                throw new UserException("user.blocked", phonenumber);
            }
            // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
            // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
            return buildLoginUser(userMapper.selectUserByPhonenumber(phonenumber));
        });
    }

    @Override
    public LoginUser getLoginUserInfoByEmail(String email, String tenantId) {
        return TenantHelper.dynamic(tenantId, () -> {
            SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
                    .select(SysUser::getEmail, SysUser::getStatus)
                    .eq(SysUser::getEmail, email));
            if (ObjectUtil.isNull(user)) {
                throw new UserException("user.not.exists", email);
            }
            if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
                throw new UserException("user.blocked", email);
            }
            // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
            // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
            return buildLoginUser(userMapper.selectUserByEmail(email));
        });
    }

    @Override
    public XcxLoginUser getUserInfoByOpenid(String openid) throws UserException {
        // todo 自行实现 userService.selectUserByOpenid(openid);
        SysUser sysUser = new SysUser();
        if (ObjectUtil.isNull(sysUser)) {
            // todo 用户不存在 业务逻辑自行实现
        }
        if (UserStatus.DISABLE.getCode().equals(sysUser.getStatus())) {
            // todo 用户已被停用 业务逻辑自行实现
        }
        // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
        // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
        XcxLoginUser loginUser = new XcxLoginUser();
        loginUser.setUserId(sysUser.getUserId());
        loginUser.setUsername(sysUser.getUserName());
        loginUser.setNickname(sysUser.getNickName());
        loginUser.setUserType(sysUser.getUserType());
        loginUser.setOpenid(openid);
        return loginUser;
    }

    /**
     * 构建登录用户
     */
    @Override
    public LoginUser buildLoginUser(SysUserVo userVo) {
        LoginUser loginUser = getLoginUser(userVo);
        loginUser.setMenuPermission(permissionService.getMenuPermission(userVo.getUserId()));
        loginUser.setRolePermission(permissionService.getRolePermission(userVo.getUserId()));
        return loginUser;
    }

    /**
     * 校验租户
     *
     * @param tenantId 租户ID
     */
    @Override
    public void checkTenant(String tenantId) {
        if (!TenantHelper.isEnable()) {
            return;
        }
        if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) {
            return;
        }
        if (StringUtils.isBlank(tenantId)) {
            throw new TenantException("tenant.number.not.blank");
        }
        SysTenantVo tenant = tenantService.queryByTenantId(tenantId);
        //输出异常
        checkTenantException(tenant, tenantId);
    }


    /**
     * 更新用户信息
     *
     * @param userId 用户ID
     * @param ip     IP地址
     */
    @Override
    public void recordLoginInfo(Long userId, String ip) {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userId);
        sysUser.setLoginIp(ip);
        sysUser.setLoginDate(DateUtils.getNowDate());
        sysUser.setUpdateBy(userId);
        DataPermissionHelper.ignore(() -> userMapper.updateById(sysUser));
    }
}
